package com.hua.config;

import com.hua.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.stereotype.Component;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;

/**
 * @author ONE-X
 * @date 2020/11/09
 */
@SuppressWarnings("all")
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	// 失败验证
	@Autowired
	@Qualifier("customAuthenticationFailureHandler")
	AuthenticationFailureHandler authenticationFailureHandler;

	// 成功验证
	@Autowired
	@Qualifier("myAuthenticationSuccessHandler")
	AuthenticationSuccessHandler authenticationSuccessHandler;

	// 数据源
	@Autowired
	DataSource dataSource;

	@Autowired
	private UserServiceImpl userService;

	// 用户认证
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
	}

	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
		jdbcTokenRepository.setDataSource(dataSource);
		return jdbcTokenRepository;
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 注销
		http.logout().logoutUrl("/logout").logoutSuccessUrl("/index");


		http.formLogin()
				.loginPage("/login")
				.loginProcessingUrl("/loginUser")    // 登录处理页面
				.failureHandler(authenticationFailureHandler)    // 失败
				.successHandler(authenticationSuccessHandler)    // 登录成功
				.and()
				.rememberMe() // 启用rememberMe
				.tokenRepository(persistentTokenRepository()) // 配置 token 持久化仓库
				.tokenValiditySeconds(6000000) // remember 过期时间，单为秒
				.userDetailsService(userService) // 处理自动登录逻辑
				.and()
				.authorizeRequests()
				.antMatchers("/login", "/druid/**","/user/login", "/index","/logout","/register").permitAll()    // 无需处理这些页面
				.anyRequest()
				.authenticated()
				.and()        // 记住我
				.csrf().disable();        // 关闭 csrf


	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/ckeditor/**","/bootstrap/**", "/css/**", "/editormd/**", "/images/**", "/js/**", "/layer/**");
	}


	// 密码
	@Bean
	PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
}


@Component
class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

	// 认证完毕之后每次都会经过这个方法
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {

		chain.doFilter(request, response);
	}

	// 初次认证成功后的方法
	@Override
	public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
		httpServletResponse.sendRedirect("./index");
	}
}


@Component("customAuthenticationFailureHandler")
class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {

	@Override
	public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
		httpServletRequest.getSession().setAttribute("error", "用户名或者密码错误！");

		httpServletRequest.getRequestDispatcher("/login").forward(httpServletRequest, httpServletResponse);
	}
}
